Skip to content

Add @e2b/id: prefixed IDs for E2B resources - #1627

Draft
mishushakov wants to merge 1 commit into
mainfrom
prefixed-id-packages
Draft

Add @e2b/id: prefixed IDs for E2B resources#1627
mishushakov wants to merge 1 commit into
mainfrom
prefixed-id-packages

Conversation

@mishushakov

@mishushakov mishushakov commented Jul 30, 2026

Copy link
Copy Markdown
Member

Stack: 1 of 2. This is the JavaScript half; #1628 adds the Python twin on top. Split for review — this PR is self-contained and its tests pass with packages/python-id absent.

@e2b/id gives every service and SDK one spelling for a resource ID: a three-character kind prefix, an underscore, and the 26-character rotated base32 encoding of a UUID. No dependencies, and no runtime-specific API — a test asserts src reaches for nothing but platform globals, so it works in Workers, Deno, Bun and browsers with no compat flags.

The rotation is the point: a UUIDv7 leads with a 48-bit millisecond timestamp, so unrotated encodings of IDs minted together share a long common prefix and the leading characters barely move for months. Rotating left by 16 puts 10 characters of random bits in front and the timestamp from index 10 — at the cost of encoded order no longer following time, which the tests state outright so nobody indexes on it.

Part of SDK-303

Usage

import { createId, decodeId, encodeId, isId, parseId } from '@e2b/id'

createId('project')                                          // 'prj_uk75vf2v7iagp2kgn7pfze3car'
encodeId('volume', '019fa519-bfc5-784d-9386-a5d7a93a692a')   // 'vol_uxl2sotjfiagp2kgn7yv4e3e4g'
decodeId('volume', 'vol_uxl2sotjfiagp2kgn7yv4e3e4g')         // '019fa519-bfc5-784d-9386-a5d7a93a692a'
parseId('vol_uxl2sotjfiagp2kgn7yv4e3e4g')                    // { kind: 'volume', uuid: '019fa519-…' }
isId('project', 'vol_uxl2sotjfiagp2kgn7yv4e3e4g')            // false

Id<K> is a template literal type, so a mismatch is a compile error and isId narrows:

function open(volume: Id<'volume'>) {}
open(createId('project'))               // Argument of type 'prj_${string}' is not assignable
if (isId('volume', input)) open(input)  // narrowed to Id<'volume'>

Errors carry a reason ('kind' | 'prefix' | 'length' | 'alphabet' | 'canonical' | 'uuid') plus actualKind, so callers branch on a field rather than on message prose.

kind project workspace volume sandbox user group
prefix prj wrk vol sbx usr grp

Notes for reviewers

  • No ID contains 0, 1, 8 or 9 — the alphabet is RFC 4648 base32 lowercased (a-z2-7), exactly what base64.b32encode produces. If you have seen prefixed-ID examples elsewhere with other digits, those were illustrative placeholders (confirmed); this implements the reference format verbatim and every golden vector reproduces exactly.
  • The kind registry is closed. A copy pinned to 0.1.0 rejects a structurally valid ID for a kind added later. Known and accepted for now, to be handled before a seventh kind ships.
  • Not published. changeset publish releases any public workspace package whose version is absent from the registry, so a public @e2b/id would ship as a side effect of the next unrelated release — and creating a new name in the @e2b scope needs rights the release token may not have, which fails after the version-bump commit (the SDK-298 shape). Marked private until that is arranged.

Verification

108 tests, plus lint/typecheck/build clean. Beyond the suite: the built dist contains zero node: imports, and the interop suite drives python3 over the whole 1303-value corpus to hold the "any language can read these with its standard library" claim to account rather than trusting it.

Golden vectors were computed with Python's b32encode rather than captured from this implementation, so they check it rather than record it. CORPUS_DIGEST is the cross-implementation contract that #1628 pins from the other side.

🤖 Generated with Claude Code

@linear-code

linear-code Bot commented Jul 30, 2026

Copy link
Copy Markdown

SDK-303

@cla-bot cla-bot Bot added the cla-signed label Jul 30, 2026
@changeset-bot

changeset-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 27a952b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@cursor

cursor Bot commented Jul 30, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
New standalone codec library and CI only; no changes to auth, billing, or existing SDK runtime paths.

Overview
packages/js-id/src/uuid.ts still comments that the build targets es2017, but tsconfig.json and tsdown.config.ts use es2022.

.github/workflows/id_tests.yml and sdk_tests.yml copy refer to ID packages (plural) and a no-secrets codec workflow, but this diff only adds build/test steps for packages/js-id, not a Python package or second workflow leg.

Reviewed by Cursor Bugbot for commit 27a952b. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Package Artifacts

Built from 8df97be. Download artifacts from this workflow run.

JS SDK (e2b@2.36.2-prefixed-id-packages.0):

npm install ./e2b-2.36.2-prefixed-id-packages.0.tgz

CLI (@e2b/cli@2.16.1-prefixed-id-packages.0):

npm install ./e2b-cli-2.16.1-prefixed-id-packages.0.tgz

Python SDK (e2b==2.35.0+prefixed.id.packages):

pip install ./e2b-2.35.0+prefixed.id.packages-py3-none-any.whl

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ebc5708. Configure here.

Comment thread packages/js-id/src/id.ts
'prefix',
`"${id}" is a ${named} ID, not a ${kind} ID.`,
named
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong kind lookup without separator

Medium Severity

When decodeId rejects an ID with no underscore, id.indexOf(SEPARATOR) is -1, so id.slice(0, -1) drops the last character before the prefix lookup. That can set actualKind and the error message from a truncated string, and disagrees with Python's split behavior on the same input.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit ebc5708. Configure here.

A three-character kind prefix, an underscore, and the 26-character rotated
base32 encoding of a UUID:

    prj_uk75vf2v7iagp2kgn7pfze3car
    sbx_blo7looa3eagp2kgn75n47fkrk

The rotation is the point. A UUIDv7 leads with a 48-bit millisecond
timestamp, so unrotated encodings of IDs minted together share a long
common prefix and the leading characters barely move for months.
Rotating left by 16 puts 10 characters of random bits in front and the
timestamp from index 10 — at the cost of encoded order no longer
following time, which the tests state outright so nobody indexes on it.

The alphabet is exactly the one base64.b32encode produces, so any
language can read these IDs with its standard library and no tables. The
interop suite drives python3 over the whole corpus to hold that claim to
account rather than trusting it.

No dependencies, and no runtime-specific API: a test asserts src reaches
for nothing but platform globals, so the package works in Workers, Deno,
Bun and browsers with no compat flags.

Not published yet. `changeset publish` releases any public workspace
package whose version is absent from the registry, so a public @e2b/id
would ship as a side effect of the next unrelated release — and creating
a new name in the @e2b scope needs rights the release token may not
have, which fails after the version-bump commit (the SDK-298 shape).
Marked private until that is arranged.

Co-Authored-By: Claude <noreply@anthropic.com>
@mishushakov
mishushakov force-pushed the prefixed-id-packages branch from ebc5708 to 27a952b Compare July 30, 2026 16:12
@mishushakov mishushakov changed the title Add @e2b/id and e2b_id: prefixed IDs for E2B resources Add @e2b/id: prefixed IDs for E2B resources Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant